package parsetree;

import java.io.Externalizable;
import java.io.Serializable;
import java.util.List;

import javax.swing.event.DocumentEvent.ElementChange;
import javax.swing.text.AbstractDocument.LeafElement;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;

import metagrammar.Type;
import metagrammar.Typed;

/**
 * An Element represents a node on the parse tree of some grammar.
 * 
 * @author Joshua Lockerman
 */
public interface Element extends javax.swing.text.Element, Typed, Serializable, Externalizable {
    
    /**
     * Gets the number of children of this Element. A {@link LeafElement} always returns 0.
     * @return the number of children of this Element.
     */
    public int getChildCount();
    
    @Override
    public int getEndOffset();
    
    @Override
    public Element getElement(int index);
    
    @Override
    public Type getType();
    
    public BranchElement getParent();
    
    public ParseTree getParseTree();
    
    @Override
    public int getStartOffset();
    
    public boolean hasChildren();
    
    @Override
    public boolean isLeaf();
    
    
    /**
     * Replace the {@link AttributeSet} for this element with a new one
     * containing the contents of attributes
     * @param attributes the contents of the new {@link AttributeSet}
     */
    public void setAttributes(AttributeSet attributes);
    
    public BranchElement setParent(AbstractBranchElement newParent);
    
    /**
     * Splits the Element about the model offset. More precisely returns an array
     * number of elements {E0 E1 ... Ei Ei+1 ... En} such that,
     * </br>Ej.getStartOffset() == Ej+1.getEndOffset(),
     * </br>E0.getStartOffset() == this.getStartOffset(),
     * </br>En.getEndOffset() == this.getEndOffset(),
     * </br>and Ei.getStartOffset() == Ei+1.getEndOffset() == modelOffset
     * @param modelOffset The offset within the Document around which this should be split
     * @return an array, of length >= 2 containing the result of the split
     * @throws BadLocationException
     * @see {@link #getStartOffset()}</br>{@link #getEndOffset()}</br>{@link #merge(Element)}
     */
    public Element[] split(int modelOffset) throws BadLocationException;
    
    /**
     * Updates this subtree in response to inserts in the document.
     * @param change the change which necessitates the update.
     * @param attributes the attributes of the change.
     * @return true if this subtree was changed.
     */
    public List<ElementChange> insertUpdate(Insert change, AttributeSet attributes);
    
    /**
     * Updates this subtree in response to removals in the document.
     * @param change the change which necessitates the update.
     * @return true if this subtree was changed.
     */
    public List<ElementChange> postRemoveUpdate(Removal change);
    
    /**
     * Attempts to merge this element with the supplied Element. If
     * successful will return the root of the subtree created. merges are
     * only possible for adjacent elements.
     * @param element
     * @return
     */
    public Element merge(Element element);
    
    public abstract void addAttributes(AttributeSet newAttributes);
}